#include "Matrix.h"

Matrix::Matrix(void): width(0), height(0), m(NULL)
{
}
Matrix::Matrix(int pWidth, int pHeight):width(pWidth), height(pHeight)
{
	assert(pWidth >=0 && pHeight >=0);
	m = new float[width*height];
	setIdentity();
}
Matrix::Matrix(const Matrix& value)
{
}
Matrix::~Matrix(void)
{
	if(m != NULL)
	{
		delete [] m;
	}
}

void Matrix::setValue(int x, int y, float value)
{
	assert(x >=0 && y >=0 && x + y*width < width*height);
	m[x + y*width] = value;
}
float Matrix::getValue(int x, int y) const
{
	assert(x >=0 && y >=0 && x + y*width < width*height);
	return m[x + y*width];
}
void Matrix::setWidth(int pWidth)
{
	setDimensions(pWidth, height);
}
void Matrix::setHeight(int pHeight)
{
	setDimensions(width, pHeight);
}
void Matrix::setDimensions(int w, int h)
{
	assert(w >=0 && h >=0 );
	if(w != width || h != height)
	{
		if(m != NULL)
		{


			float* mAux = m;
			float* dest = new float[w*h];

			for(int i = 0; i< h; i++)
			{
				for(int j = 0; j< w; j++)
				{
					int pos = j + i*w;

					if(i >= height || j >= width)
					{	
						dest[pos] = i == j ? 1.0f : 0.0f;
					}
					else 
					{
						dest[pos] = mAux[j + i*width];
					}
				}
			}

			delete [] m;
			width = w;
			height = h;

			m = dest;



		}
		else
		{
			m = new float[w*h];
			width = w;
			height = h;
			setIdentity();
		}
	}
}
int Matrix::getWidth() const
{
	return width;
}
int Matrix::getHeight() const
{
	return height;
}
void Matrix::add(const Matrix& other)
{

	if( other.getHeight() != height || other.getWidth() != width )
	{
		float w = std::max(width, other.width);
		float h = std::max(height, other.height);

		float* addition = new float[w*h];

		for(int i = 0; i< h ; i++)
		{
			for(int j = 0; j< w ; j++)
			{
				int pos = j + i*w;
				float x = 0.0f;
				if(i < height && j < width )
				{
					x = m[j + i*width];
				}
				float y = 0.0f;
				if(i < other.height && j < other.width )
				{
					y = other.m[j + i*other.width];
				}
				addition[pos] = x+y;
			}
		}

		delete [] m;
		width = w;
		height = h;
		m = addition;
	}
	else
	{
		for(int i = 0; i< height ; i++)
		{
			for(int j = 0; j< width ; j++)
			{
				int pos = j + i*width;
				m[pos] += other.getValue(j, i);
			}
		}
	}

}
void Matrix::multiply(const Matrix& other)
{
	if(width == other.height)
	{
		float* result = new float[other.width*height];
		for(int i = 0; i< height ; i++)
		{
			for(int j = 0; j< other.width; j++)
			{
				float r = 0.0f;
				for(int k = 0; k< width; k++)
				{
					r += m[i*width + k]*other.m[k*other.width + j];
				}
				result[j + other.width*i] = r;
			}
		}

		delete [] m;
		width = other.width;
		m = result;


	}
}
void Matrix::transpose()
{
	float* transpose = new float[width*height];
	for(int j = 0; j< width; j++)
	{
		for(int i = 0; i< height ; i++)
		{
			int pos = j + i*width;
			transpose[i + j*height] = m[pos];
		}

	}
	delete [] m;

	float w = width;
	width = height;
	height = w;
	m = transpose;
}
void Matrix::operator=(const Matrix& source)
{
	width = source.width;
	height = source.height;

	if(m != NULL)
	{
		delete [] m;
	}

	m = new float[width*height];

	for(int i = 0; i< height ; i++)
	{
		for(int j = 0; j< width; j++)
		{
			int pos = j + i*width;
			m[pos] = source.m[pos];
		}
	}
}
// -----methodes suplementaires-----
void Matrix::setIdentity()
{
	for(int i = 0; i< height; i++)
	{
		for(int j = 0; j< width; j++)
		{
			if(i==j)
			{
				m[j + i*width] =  1.0f;
			}
			else
			{
				m[j + i*width] =  0.0f;
			}
		}
	}
}

void Matrix::copy(float* mAux)
{
	for(int i = 0; i< height ; i++)
	{
		for(int j = 0; j< width; j++)
		{
			int pos = j + i*width;
			mAux[pos] = m[pos];
		}
	}
}




